/*
 * Copyright (c) 2007 jNetX.
 * http://www.jnetx.com
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * jNetX. You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license
 * agreement you entered into with jNetX.
 *
 * $Id$
 */
package com.jnetx.javax.sip;

import com.jnetx.javax.sip.trans.TCPTransportManager;
import com.jnetx.javax.sip.trans.UDPTransportManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.sip.*;
import javax.sip.address.Router;
import java.util.*;

/**
 * @author <a href="mailto:dparhonin@jnetx.ru">Dmitry Parhonin</a>
 * @version $Revision$
 */
public class SipStackImpl implements SipStack {
    private final static Log log = LogFactory.getLog(SipStackImpl.class);
    private List<SipProvider> sipProviders = new ArrayList<SipProvider>();
    private List<ListeningPoint> listeningPoints = new ArrayList<ListeningPoint>();
    private Map<String, TransportManager> transportManagers = new HashMap<String, TransportManager>(2); //we suppose to have only UDP and TCP here

    private Router router;
    private SipStackConfig config;

    public SipStackImpl(Properties props) {
        SipStackPropertyConfigurator configurator = new SipStackPropertyConfigurator(this);
        config = configurator.createConfig(props);
        if (log.isDebugEnabled()) log.debug("The stack config has been created: " + config);
    }

    private void loadTransportManagers(SipStackConfig config) {
        //Load default transport managers
        transportManagers.put("TCP", new TCPTransportManager());
        transportManagers.put("UDP", new UDPTransportManager());
    }

    void setRouter(Router router) {
        this.router = router;
    }

    public SipProvider createSipProvider(ListeningPoint listeningPoint) throws ObjectInUseException {
        if (log.isDebugEnabled()) log.debug("createSipProvider(listeningPoint=" + listeningPoint + ")");
        final SipProvider sipProvider = new SipProviderImpl(this);
        try {
            sipProvider.addListeningPoint(listeningPoint);
        } catch (TransportAlreadySupportedException e) {
            log.error("Cannot add a listening point to a newly created SipProvider!", e);
        }
        sipProviders.add(sipProvider);
        return sipProvider;
    }

    public void deleteSipProvider(SipProvider sipProvider) throws ObjectInUseException {
        if (log.isDebugEnabled()) log.debug("deleteSipProvider(sipProvider=" + sipProvider + ")");
        sipProviders.remove(sipProvider);
    }

    public Iterator getSipProviders() {
        return sipProviders.listIterator();
    }

    /**
     * @deprecated
     */
    public ListeningPoint createListeningPoint(int port, String transport) throws TransportNotSupportedException, InvalidArgumentException {
        if (log.isDebugEnabled()) log.debug("createListeningPoint(port=" + port + ",transport=" + transport + ")");
        if (config.getIPAddress() == null) throw new TransportNotSupportedException("No IP address is specified!");
        return createListeningPoint(config.getIPAddress(), port, transport);
    }

    public ListeningPoint createListeningPoint(String ipAddress, int port, String transport) throws TransportNotSupportedException, InvalidArgumentException {
        if (log.isDebugEnabled())
            log.debug("createListeningPoint(ipAddress=" + ipAddress + ",port=" + port + ",transport=" + transport + ")");
        ListeningPoint result = new ListeningPointImpl(ipAddress, port, transport);
        listeningPoints.add(result);
        return result;
    }

    public void deleteListeningPoint(ListeningPoint listeningPoint) throws ObjectInUseException {
        if (log.isDebugEnabled()) log.debug("deleteListeningPoint(listeningPoint=" + listeningPoint + ")");
        listeningPoints.remove(listeningPoint);
    }

    public Iterator getListeningPoints() {
        return listeningPoints.iterator();
    }

    public String getStackName() {
        return config.getName();
    }

    public String getIPAddress() {
        return config.getIPAddress();
    }

    public Router getRouter() {
        return router;
    }

    public void stop() {
        //todo Implement this
    }

    public void start() throws SipException {
        for (ListeningPoint listeningPoint: listeningPoints) {
            TransportManager tm = transportManagers.get(listeningPoint.getTransport());
            tm.startListeningPoint(listeningPoint);
        }
    }

    /**
     * @deprecated
     */
    public boolean isRetransmissionFilterActive() {
        return false;
    }

    public String toString() {
        return "SipStackImpl{name=" + config.getName() + "}";
    }
}
/*
 * $Log$
 */